﻿using System;
using System.Xml;
using System.Xml.Serialization;
using System.Collections;
using System.Collections.Generic;
using XmlVisualizer.Controllers;
using XmlVisualizer.Views;
using System.Windows;
using System.Windows.Controls;
using System.Collections.ObjectModel;
using System.Xml.Schema;
using System.IO;
using System.Text;
using System.Configuration;

namespace XmlVisualizer.Models
{
    enum docs : int { XML, XSD, DTD };

    /// <summary>
    /// Contains all the data essential for the application.
    /// Controls the behaviour of the program.
    /// </summary>
    public class ApplicationModel : IModel
    {
        #region M E M B E R S
        private XmlModel _xmlModel;
        private XmlController _xmlController;

        private XsdModel _xsdModel;
        private XsdController _xsdController;

        private IView _appView;
        private int _mode;
        private ArrayList _observers = new ArrayList();
        #endregion

        #region P R O P E R T I E S

        public XmlModel XMLModel
        {
            get { return _xmlModel; }
        }

        public XmlController XMLController
        {
            get { return _xmlController; }
        }

        public XsdModel XSDModel
        {
            get { return _xsdModel; }
        }

        public XsdController XSDController
        {
            get { return _xsdController; }
        }

        public IView appView
        {
            get { return _appView; }
        }

        public int Mode
        {
            get { return _mode; }
        }

        #endregion

        #region M E T H O D S

        /// <summary>
        /// Shuts down the application.
        /// </summary>
        public void ApplicationShutdown()
        {
            foreach (Observer o in _observers)
                o.unexpectedShutdownNotify();

            Application.Current.Shutdown();
        }

        /// <summary>
        /// ApplicationModel contructor.
        /// </summary>
        /// <param name="view"></param>
        public ApplicationModel(IView view)
        {
            _appView = view;
        }

        /// <summary>
        /// Opens the desired file
        /// </summary>
        /// <param name="filename">file to open</param>
        public void OpenFile(String filename)
        {
            String[] split = filename.Split(new Char[] { '.' });
            String extension = split[split.Length - 1];

            switch (extension.ToLower())
            {
                case "xml":
                    _mode = (int)docs.XML;
                    _xmlModel = new XmlModel(this);
                    _xmlController = new XmlController(ref _xmlModel, ref _appView);
                    _xmlModel.OpenFile(filename);
                    break;
                case "xsd":
                    _mode = (int)docs.XSD;
                    _xsdModel = new XsdModel(this);
                    _xsdController = new XsdController(ref _xsdModel, ref _appView);
                    _xsdModel.OpenFile(filename);
                    break;
                case "dtd":

                    _mode = (int)docs.DTD;
                    break;
                default:
                    break;
            }
        }

        public void SaveFile(string filename)
        {
            throw new NotImplementedException();
        }

        public void DrawDiagram()
        {
            throw new NotImplementedException();
        }

        public void RegisterObserver(Observer controller)
        {
            _observers.Add(controller);
        }

        public void RemoveObserver(Observer controller)
        {
            _observers.Remove(controller);
        }

        #endregion

        #region IModel Members


        public string GetOuterXml()
        {
            throw new NotImplementedException();
        }

        #endregion
    };

    public class XmlModel : IModel
    {
        #region M E M B E R S

        private XmlDocument document;
        private ArrayList observers;
        private ApplicationModel appModel;
        private XmlNode _documentElement;

        private Hashtable _HTnode2visual = new Hashtable();
        private ObservableCollection<VisualNode> visualNodes = new ObservableCollection<VisualNode>();

        #endregion

        #region P R O P E R T I E S

        public ObservableCollection<VisualNode> VisualNodes
        {
            get { return visualNodes; }
        }

        public XmlDocument XMLDocument
        {
            get { return document; }
        }

        public XmlNode documentElement
        {
            get { return _documentElement; }
        }

        #endregion

        #region M E T H O D S

        public XmlModel(ApplicationModel applicationModel)
        {
            appModel = applicationModel;
            observers = new ArrayList();
        }

        public VisualNode getVisualFromNode(ref XmlNode node)
        {
            return _HTnode2visual[node] as VisualNode;
        }

        // default templates
        private String appearanceDefaultTemplate = "AppearanceProcess";
        private String connectorDecoratorDefaultTemplate = "ConnectorDecoratorDefaultTemplate";

        /// <summary>
        /// Traverses through the Xml document and creates own visual nodes
        /// to create a graphical representation of the document.
        /// </summary>
        /// <param name="node">XmlNode to load</param>
        /// <param name="parent">parent VisualNode of the XmlNode</param>
        public void Load(XmlNode node, VisualNode parent)
        {
            // creating the visual node
            VisualNode visualNode = new VisualNode();
            visualNode.Data = node;
            visualNode.NodeType = node.NodeType;
            visualNode.Position = new Point(0.0, 0.0);
            visualNode.AppearanceTemplate = Application.Current.FindResource(appearanceDefaultTemplate) as ControlTemplate;
            visualNode.ConnectorDecoratorTemplate = Application.Current.FindResource(connectorDecoratorDefaultTemplate) as ControlTemplate;

            // add the node to the parent as a child
            if (parent != null)
                parent.Children.Add(visualNode);

            if (node.NodeType != XmlNodeType.Whitespace)
            {
                // add the visualNode to the list of all the visual nodes and the hashtable
                visualNodes.Add(visualNode);
                _HTnode2visual.Add(node, visualNode);
            }

            if (parent != null)
                parent.Children.Add(visualNode);

            if (node.Attributes != null)
            {
                int atrs = node.Attributes.Count;
                for (int i = 0; i < atrs; ++i)
                {
                    VisualNode attributes = new VisualNode();

                    attributes.Data = node.Attributes[i];
                    attributes.NodeType = node.Attributes[i].NodeType;
                    attributes.Position = new Point(0.0, 0.0);
                    attributes.AppearanceTemplate = Application.Current.FindResource(appearanceDefaultTemplate) as ControlTemplate;
                    attributes.ConnectorDecoratorTemplate = Application.Current.FindResource(connectorDecoratorDefaultTemplate) as ControlTemplate;

                    visualNode.Attributes.Add(attributes);
                }
            }

            foreach (XmlNode n in node.ChildNodes)
            {
                Load(n, visualNode);
            }

        }

        #endregion

        #region IModel Members

        /// <summary>
        /// Loads the XML file into memory and tells the
        /// observers to show it.
        /// </summary>
        /// <param name="filename"></param>
        public void OpenFile(string filename)
        {
            try
            {
                document = new XmlDocument();
                document.PreserveWhitespace = true;
                document.Load(filename);
                _documentElement = document.DocumentElement;

                Load(document.DocumentElement, null);
            }
            catch (System.Exception e)
            {
                String message = e.Message;
                MessageBox.Show(message);
            }

            foreach (Observer o in observers)
            {
                o.showFile();
            }
        }

        public void SaveFile(string filename)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Registers the observer.
        /// </summary>
        /// <param name="controller">observer to register</param>
        public void RegisterObserver(Observer controller)
        {
            observers.Add(controller);
        }

        /// <summary>
        /// Removes the observer from the list.
        /// </summary>
        /// <param name="controller">observer to remove</param>
        public void RemoveObserver(Observer controller)
        {
            observers.Remove(controller);
        }

        /// <summary>
        /// Gets the whole xml markup from the document.
        /// </summary>
        /// <returns>xml markup of the document as String</returns>
        public String GetOuterXml()
        {
            return document.OuterXml;
        }

        #endregion
    }

    public class XsdModel : IModel
    {
        #region M E M B E R S

        private ArrayList observers;
        private ApplicationModel appModel;
        private XmlSchemaVisual visualSchema;

        #endregion

        #region P R O P E R T I E S

        public XmlSchemaVisual VisualSchema
        {
            get { return visualSchema; }
            set { visualSchema = value; }
        }

        #endregion

        #region M E T H O D S

        public XsdModel(ApplicationModel applicationModel)
        {
            appModel = applicationModel;
            observers = new ArrayList();
        }

        #endregion

        static void ValidationCallback(object sender, ValidationEventArgs args)
        {
            String errorText = "";
            if (args.Severity == XmlSeverityType.Warning)
                errorText = "WARNING: ";
            else if (args.Severity == XmlSeverityType.Error)
                errorText = "ERROR: ";

            MessageBox.Show(errorText + args.Message);
        }

        #region XmlSchema fill functions

        protected XmlSchemaVisualAnnotation fillVisualAnnotation(ref XmlSchemaAnnotation annotation, ref XmlSchemaObject parent)
        {
            if (annotation != null)
            {
                XmlSchemaVisualAnnotation ann = new XmlSchemaVisualAnnotation(ref annotation);
                ann.Parent = parent;

                return ann;
            }
            else
            {
                return null;
            }
        }

        protected XmlSchemaObject fillVisualAttribute(ref XmlSchemaObject attribute, ref XmlSchemaObject parent)
        {
            if (attribute != null)
            {
                // attribute can be XmlSchemaAttribute or XmlSchemaAttributeGroupRef
                if (attribute.GetType() == typeof(XmlSchemaAttribute))
                {
                    XmlSchemaAttribute att = attribute as XmlSchemaAttribute;
                    XmlSchemaVisualAttribute attr = new XmlSchemaVisualAttribute(ref att);
                    // Annotation
                    XmlSchemaAnnotation annotation = att.Annotation;
                    XmlSchemaObject aParent = attr as XmlSchemaObject;
                    XmlSchemaVisualAnnotation visualAnnotation = fillVisualAnnotation(ref annotation, ref aParent);
                    attr.Annotation = visualAnnotation;

                    // Attribute contains simple type
                    XmlSchemaSimpleType simpleType = att.AttributeSchemaType;
                    XmlSchemaVisualSimpleType visualSimpleType = fillVisualSimpleType(ref simpleType, ref aParent);
                    attr.AttributeSchemaType = visualSimpleType;

                    attr.Parent = parent;
                    return attr;
                }
                else if (attribute.GetType() == typeof(XmlSchemaAttributeGroupRef))
                {
                    XmlSchemaAttributeGroupRef attGrRef = attribute as XmlSchemaAttributeGroupRef;
                    XmlSchemaVisualAttributeGroupRef visualAttributeGroupRef = new XmlSchemaVisualAttributeGroupRef(ref attGrRef);
                    // Annotation
                    XmlSchemaAnnotation annotation = attGrRef.Annotation;
                    XmlSchemaObject aParent = attGrRef as XmlSchemaObject;
                    XmlSchemaVisualAnnotation visualAnnotation = fillVisualAnnotation(ref annotation, ref aParent);
                    visualAttributeGroupRef.Annotation = visualAnnotation;
                    visualAttributeGroupRef.Parent = parent;

                    return visualAttributeGroupRef;
                }
                else
                {
                    return null;
                }
            }
            else
            {
                return null;
            }
        }

        protected XmlSchemaVisualGroup fillVisualGroup(ref XmlSchemaGroup group)
        {
            if (group != null)
            {
                XmlSchemaVisualGroup gr = new XmlSchemaVisualGroup(ref group);

                // Annotation
                XmlSchemaAnnotation annotation = group.Annotation;
                XmlSchemaObject parent = gr as XmlSchemaObject;
                XmlSchemaVisualAnnotation visualAnnotation = fillVisualAnnotation(ref annotation, ref parent);
                //visualAnnotation.Parent = gr;
                gr.Annotation = visualAnnotation;

                // Particle
                XmlSchemaGroupBase particle = group.Particle;
                XmlSchemaVisualGroupBase visualParticle = fillVisualGroupBase(ref particle);
                visualParticle.Parent = gr;
                gr.Particle = visualParticle;

                return gr;
            }
            else
            {
                return null;
            }
        }

        protected XmlSchemaVisualGroupBase fillVisualGroupBase(ref XmlSchemaGroupBase particle)
        {
            if (particle != null)
            {
                // Annotation
                XmlSchemaAnnotation annotation = particle.Annotation;
                XmlSchemaObject parent = particle as XmlSchemaObject;
                XmlSchemaVisualAnnotation visualAnnotation = fillVisualAnnotation(ref annotation, ref parent);
                //visualAnnotation.Parent = particle;

                if (particle.GetType() == typeof(XmlSchemaChoice))
                {
                    XmlSchemaChoice choice = particle as XmlSchemaChoice;
                    XmlSchemaVisualChoice visualChoice = fillVisualChoice(ref choice);
                    visualChoice.Annotation = visualAnnotation;

                    return visualChoice;
                }
                else if (particle.GetType() == typeof(XmlSchemaAll))
                {
                    XmlSchemaAll all = particle as XmlSchemaAll;
                    XmlSchemaVisualAll visualAll = fillVisualAll(ref all);
                    visualAll.Annotation = visualAnnotation;

                    return visualAll;
                }
                else if (particle.GetType() == typeof(XmlSchemaSequence))
                {
                    XmlSchemaSequence sequence = particle as XmlSchemaSequence;
                    XmlSchemaVisualSequence visualSequence = fillVisualSequence(ref sequence);
                    visualSequence.Annotation = visualAnnotation;

                    return visualSequence;
                }
                else
                {
                    // unknown type
                    return null;
                }
            }
            else
            {
                return null;
            }
        }

        protected XmlSchemaVisualParticle fillVisualParticle(ref XmlSchemaParticle particle)
        {
            if (particle != null)
            {
                // Annotation
                XmlSchemaAnnotation annotation = particle.Annotation;
                XmlSchemaObject parent = particle as XmlSchemaObject;
                XmlSchemaVisualAnnotation visualAnnotation = fillVisualAnnotation(ref annotation, ref parent);
                //visualAnnotation.Parent = particle;

                if (particle.GetType() == typeof(XmlSchemaChoice))
                {
                    XmlSchemaChoice choice = particle as XmlSchemaChoice;
                    XmlSchemaVisualChoice visualChoice = fillVisualChoice(ref choice);
                    visualChoice.Annotation = visualAnnotation;

                    return visualChoice;
                }
                else if (particle.GetType() == typeof(XmlSchemaAll))
                {
                    XmlSchemaAll all = particle as XmlSchemaAll;
                    XmlSchemaVisualAll visualAll = fillVisualAll(ref all);
                    visualAll.Annotation = visualAnnotation;

                    return visualAll;
                }
                else if (particle.GetType() == typeof(XmlSchemaSequence))
                {
                    XmlSchemaSequence sequence = particle as XmlSchemaSequence;
                    XmlSchemaVisualSequence visualSequence = fillVisualSequence(ref sequence);
                    visualSequence.Annotation = visualAnnotation;

                    return visualSequence;
                }
                else if (particle.GetType() == typeof(XmlSchemaAny))
                {
                    XmlSchemaAny any = particle as XmlSchemaAny;
                    XmlSchemaVisualAny visualAny = fillVisualAny(ref any, ref parent);
                    visualAny.Annotation = visualAnnotation;

                    return visualAny;
                }
                else if (particle.GetType() == typeof(XmlSchemaElement))
                {
                    XmlSchemaElement elem = particle as XmlSchemaElement;
                    XmlSchemaVisualElement visualElem = fillVisualElement(ref elem, ref parent);
                    visualElem.Annotation = visualAnnotation;

                    return visualElem;
                }
                else if (particle.GetType() == typeof(XmlSchemaGroupRef))
                {
                    XmlSchemaGroupRef groupRef = particle as XmlSchemaGroupRef;
                    // to do:
                    return null;
                }
                else
                {
                    // unknown type
                    return null;
                }
            }
            else
            {
                return null;
            }
        }

        protected XmlSchemaVisualChoice fillVisualChoice(ref XmlSchemaChoice choice)
        {
            if (choice != null)
            {
                XmlSchemaChoice c = choice;
                XmlSchemaVisualChoice visualChoice = new XmlSchemaVisualChoice(ref c);

                // Annotation
                XmlSchemaAnnotation annotation = choice.Annotation;
                XmlSchemaObject parent = visualChoice as XmlSchemaObject;
                XmlSchemaVisualAnnotation visualAnnotation = fillVisualAnnotation(ref annotation, ref parent);
                //visualAnnotation.Parent = visualChoice;

                visualChoice.Items = new XmlSchemaObjectCollection();
                foreach (XmlSchemaObject o in choice.Items)
                {
                    if (o.GetType() == typeof(XmlSchemaElement))
                    {
                        XmlSchemaElement e = o as XmlSchemaElement;
                        XmlSchemaVisualElement visualElement = fillVisualElement(ref e);
                        visualElement.Parent = visualChoice;
                        visualChoice.Items.Add(visualElement);
                    }
                    else if (o.GetType() == typeof(XmlSchemaGroupRef))
                    {
                        XmlSchemaGroupRef r = o as XmlSchemaGroupRef;
                        XmlSchemaVisualGroupRef visualGroupRef = fillVisualGroupRef(ref r);
                        visualGroupRef.Parent = visualChoice;
                        visualChoice.Items.Add(visualGroupRef);
                    }
                    else if (o.GetType() == typeof(XmlSchemaChoice))
                    {
                        XmlSchemaChoice c2 = o as XmlSchemaChoice;
                        XmlSchemaVisualChoice visualChoice2 = fillVisualChoice(ref c2);
                        visualChoice2.Parent = visualChoice;
                        visualChoice.Items.Add(visualChoice2);
                    }
                    else if (o.GetType() == typeof(XmlSchemaSequence))
                    {
                        XmlSchemaSequence s = o as XmlSchemaSequence;
                        XmlSchemaVisualSequence visualSequence = fillVisualSequence(ref s);
                        visualSequence.Parent = visualChoice;
                        visualChoice.Items.Add(visualSequence);
                    }
                    else if (o.GetType() == typeof(XmlSchemaAny))
                    {
                        XmlSchemaAny any = o as XmlSchemaAny;
                        XmlSchemaVisualAny visualAny = fillVisualAny(ref any);
                        visualAny.Parent = visualChoice;
                        visualChoice.Items.Add(visualAny);
                    }
                    else
                    {
                        // unknown type
                    }
                }
                return visualChoice;
            }
            else
            {
                return null;
            }
        }

        protected XmlSchemaVisualGroupRef fillVisualGroupRef(ref XmlSchemaGroupRef groupRef)
        {
            if (groupRef != null)
            {
                XmlSchemaGroupRef grRef = groupRef;
                XmlSchemaVisualGroupRef visualGroupRef = new XmlSchemaVisualGroupRef(ref groupRef);

                // Annotation
                XmlSchemaAnnotation annotation = groupRef.Annotation;
                XmlSchemaObject parent = visualGroupRef as XmlSchemaObject;
                XmlSchemaVisualAnnotation visualAnnotation = fillVisualAnnotation(ref annotation, ref parent);
                //visualAnnotation.Parent = visualGroupRef;

                // Particle
                XmlSchemaGroupBase p = groupRef.Particle;
                XmlSchemaVisualGroupBase particle = fillVisualGroupBase(ref p);
                particle.Parent = visualGroupRef;

                return visualGroupRef;
            }
            else
            {
                return null;
            }
        }

        protected XmlSchemaVisualSequence fillVisualSequence(ref XmlSchemaSequence sequence)
        {
            if (sequence != null)
            {
                XmlSchemaSequence s = sequence;
                XmlSchemaVisualSequence visualSequence = new XmlSchemaVisualSequence(ref s);

                // Annotation
                XmlSchemaAnnotation annotation = sequence.Annotation;
                XmlSchemaObject parent = visualSequence as XmlSchemaObject;
                XmlSchemaVisualAnnotation visualAnnotation = fillVisualAnnotation(ref annotation, ref parent);
                //visualAnnotation.Parent = visualSequence;

                // Items
                visualSequence.Items = new XmlSchemaObjectCollection();
                foreach (XmlSchemaObject o in sequence.Items)
                {
                    if (o.GetType() == typeof(XmlSchemaElement))
                    {
                        XmlSchemaElement e = o as XmlSchemaElement;
                        XmlSchemaVisualElement visualElement = fillVisualElement(ref e);
                        visualElement.Parent = visualSequence;
                        visualSequence.Items.Add(visualElement);
                    }
                    else if (o.GetType() == typeof(XmlSchemaGroupRef))
                    {
                        XmlSchemaGroupRef r = o as XmlSchemaGroupRef;
                        XmlSchemaVisualGroupRef visualGroupRef = fillVisualGroupRef(ref r);
                        visualGroupRef.Parent = visualSequence;
                        visualSequence.Items.Add(visualGroupRef);
                    }
                    else if (o.GetType() == typeof(XmlSchemaChoice))
                    {
                        XmlSchemaChoice c2 = o as XmlSchemaChoice;
                        XmlSchemaVisualChoice visualChoice2 = fillVisualChoice(ref c2);
                        visualChoice2.Parent = visualSequence;
                        visualSequence.Items.Add(visualChoice2);
                    }
                    else if (o.GetType() == typeof(XmlSchemaSequence))
                    {
                        XmlSchemaSequence s2 = o as XmlSchemaSequence;
                        XmlSchemaVisualSequence visualSequence2 = fillVisualSequence(ref s2);
                        visualSequence.Parent = visualSequence;
                        visualSequence.Items.Add(visualSequence2);
                    }
                    else if (o.GetType() == typeof(XmlSchemaAny))
                    {
                        XmlSchemaAny any = o as XmlSchemaAny;
                        XmlSchemaVisualAny visualAny = fillVisualAny(ref any);
                        visualAny.Parent = visualSequence;
                        visualSequence.Items.Add(visualAny);
                    }
                    else
                    {
                        // unknown type
                    }
                }

                return visualSequence;
            }
            else
            {
                return null;
            }
        }

        protected XmlSchemaVisualAny fillVisualAny(ref XmlSchemaAny any)
        {
            if (any != null)
            {
                XmlSchemaAny a = any;
                XmlSchemaVisualAny visualAny = new XmlSchemaVisualAny(ref a);

                // Annotation
                XmlSchemaAnnotation annotation = any.Annotation;
                XmlSchemaObject parent = visualAny as XmlSchemaObject;
                XmlSchemaVisualAnnotation visualAnnotation = fillVisualAnnotation(ref annotation, ref parent);
                //visualAnnotation.Parent = visualAny;

                return visualAny;
            }
            else
            {
                return null;
            }
        }

        protected XmlSchemaVisualAll fillVisualAll(ref XmlSchemaAll all)
        {
            if (all != null)
            {
                XmlSchemaAll a = all;
                XmlSchemaVisualAll visualAll = new XmlSchemaVisualAll(ref a);

                // Annotation
                XmlSchemaAnnotation annotation = all.Annotation;
                XmlSchemaObject parent = visualAll as XmlSchemaObject;
                XmlSchemaVisualAnnotation visualAnnotation = fillVisualAnnotation(ref annotation, ref parent);
                //visualAnnotation.Parent = visualAll;

                // Items
                visualAll.Items = new XmlSchemaObjectCollection();
                foreach (XmlSchemaElement element in all.Items)
                {
                    XmlSchemaElement e = element;
                    XmlSchemaVisualElement visualElement = fillVisualElement(ref e);
                    visualElement.Parent = visualAll;

                    visualAll.Items.Add(visualElement);
                }

                return visualAll;
            }
            else
            {
                return null;
            }
        }

        protected XmlSchemaVisualElement fillVisualElement(ref XmlSchemaElement element)
        {
            if (element != null)
            {
                XmlSchemaElement e = element;
                XmlSchemaVisualElement visualElement = new XmlSchemaVisualElement(ref e);

                // get all the info out of the element and fill the visualElement with it

                // ANNOTATION
                XmlSchemaAnnotation ann = element.Annotation;
                XmlSchemaObject parent = visualElement as XmlSchemaObject;
                XmlSchemaVisualAnnotation visualAnnotation = fillVisualAnnotation(ref ann, ref parent);
                visualElement.Annotation = visualAnnotation;

                // CONSTRAINTS
                foreach (XmlSchemaObject constraint in element.Constraints)
                {
                    if (constraint.GetType() == typeof(XmlSchemaKey))
                    {
                        XmlSchemaKey c = constraint as XmlSchemaKey;
                        visualElement.Constraints.Add(new XmlSchemaVisualKey(ref c));
                    }
                    else if (constraint.GetType() == typeof(XmlSchemaKeyref))
                    {
                        XmlSchemaKeyref c = constraint as XmlSchemaKeyref;
                        visualElement.Constraints.Add(new XmlSchemaVisualKeyref(ref c));
                    }
                    else if (constraint.GetType() == typeof(XmlSchemaUnique))
                    {
                        XmlSchemaUnique c = constraint as XmlSchemaUnique;
                        visualElement.Constraints.Add(new XmlSchemaVisualUnique(ref c));
                    }
                }
                return visualElement;
            }
            else
            {
                return null;
            }
        }

        protected XmlSchemaVisualAttributeGroup fillVisualAttributeGroup(ref XmlSchemaAttributeGroup element, ref XmlSchemaObject parent)
        {
            if (element != null)
            {
                XmlSchemaAttributeGroup attributeGroup = element;
                XmlSchemaVisualAttributeGroup visualAttributeGroup = new XmlSchemaVisualAttributeGroup(ref attributeGroup);

                // get all the info out of the element and fill the visualAttributeGroup with it

                // ANNOTATION
                XmlSchemaAnnotation ann = element.Annotation;
                XmlSchemaObject annotationParent = visualAttributeGroup as XmlSchemaObject;
                XmlSchemaVisualAnnotation visualAnnotation = fillVisualAnnotation(ref ann, ref annotationParent);
                visualAttributeGroup.Annotation = visualAnnotation;

                // ANY ATTRIBUTE
                XmlSchemaAnyAttribute any = element.AnyAttribute;
                XmlSchemaObject anyAttributeParent = visualAttributeGroup as XmlSchemaObject;
                XmlSchemaVisualAnyAttribute visualAnyAttribute = fillVisualAnyAttribute(ref any, ref anyAttributeParent);
                visualAttributeGroup.AnyAttribute = visualAnyAttribute;

                // ATTRIBUTES
                XmlSchemaObjectCollection attributes = new XmlSchemaObjectCollection();
                foreach (XmlSchemaObject att in attributeGroup.Attributes)
                {
                    XmlSchemaObject atr = att;
                    XmlSchemaObject attrParent = visualAttributeGroup as XmlSchemaObject;
                    XmlSchemaObject visualAtt = fillVisualAttribute(ref atr, ref attrParent);
                    attributes.Add(visualAtt);
                }
                visualAttributeGroup.Attributes = attributes;

                // REDEFINED ATTRIBUTE GROUP
                // to do

                visualAttributeGroup.Parent = parent;
                return visualAttributeGroup;
            }
            else
            {
                return null;
            }
        }

        protected XmlSchemaVisualComplexType fillVisualComplexType(ref XmlSchemaComplexType element, ref XmlSchemaObject parent) // DONE
        {
            if (element != null)
            {
                XmlSchemaComplexType complexType = element;
                XmlSchemaVisualComplexType visualComplexType = new XmlSchemaVisualComplexType(ref complexType);

                // get all the info out of the element and fill the visualComplexType with it

                // ANNOTATION
                XmlSchemaAnnotation ann = element.Annotation;
                XmlSchemaObject annotationParent = visualComplexType as XmlSchemaObject;
                XmlSchemaVisualAnnotation visualAnnotation = fillVisualAnnotation(ref ann, ref annotationParent);
                visualComplexType.Annotation = visualAnnotation;

                // ANY ATTRIBUTE
                XmlSchemaAnyAttribute any = element.AnyAttribute;
                XmlSchemaObject anyAttributeParent = visualComplexType as XmlSchemaObject;
                XmlSchemaVisualAnyAttribute visualAnyAttribute = fillVisualAnyAttribute(ref any, ref anyAttributeParent);
                visualComplexType.AnyAttribute = visualAnyAttribute;

                // ATTRIBUTES
                XmlSchemaObjectCollection attributes = new XmlSchemaObjectCollection();
                foreach (XmlSchemaObject att in complexType.Attributes)
                {
                    if (att.GetType() == typeof(XmlSchemaAttribute))
                    {
                        XmlSchemaObject atr = att;
                        XmlSchemaObject attrParent = visualComplexType as XmlSchemaObject;
                        XmlSchemaObject visualAtt = fillVisualAttribute(ref atr, ref attrParent);
                        attributes.Add(visualAtt);
                    }
                    else if (att.GetType() == typeof(XmlSchemaAttributeGroup))
                    {
                        XmlSchemaAttributeGroup atr = att as XmlSchemaAttributeGroup;
                        XmlSchemaObject attrParent = visualComplexType as XmlSchemaObject;
                        XmlSchemaObject visualAtt = fillVisualAttributeGroup(ref atr, ref attrParent);
                        attributes.Add(visualAtt);
                    }
                }
                visualComplexType.Attributes = attributes;

                // ATTRIBUTE USES ???

                // ATTRIBUTE WILDCARD ???

                // CONTENT MODEL
                XmlSchemaContentModel contentModel = element.ContentModel;
                XmlSchemaObject contentModelParent = element as XmlSchemaObject;
                XmlSchemaVisualContentModel visualContentModel = fillVisualContentModel(ref contentModel, ref contentModelParent);
                visualComplexType.ContentModel = visualContentModel;

                // CONTENT TYPE PARTICLE ???
                XmlSchemaParticle contentTypeParticle = element.ContentTypeParticle;
                XmlSchemaVisualParticle visualcontentTypeParticle = fillVisualParticle(ref contentTypeParticle);
                visualComplexType.ContentTypeParticle = visualcontentTypeParticle;

                visualComplexType.Parent = parent;
                return visualComplexType;
            }
            else
            {
                return null;
            }
        }

        protected XmlSchemaVisualContentModel fillVisualContentModel(ref XmlSchemaContentModel element, ref XmlSchemaObject parent)
        {
            if (element != null)
            {
                XmlSchemaContentModel contentModel = element;
                XmlSchemaVisualContentModel visualContentModel = null;

                // ANNOTATION
                XmlSchemaAnnotation ann = element.Annotation;
                XmlSchemaObject annotationParent = visualContentModel as XmlSchemaObject;
                XmlSchemaVisualAnnotation visualAnnotation = fillVisualAnnotation(ref ann, ref annotationParent);
                visualContentModel.Annotation = visualAnnotation;

                // CONTENT: XmlSchemaComplexContent or XmlSchemaSimpleContent
                if (contentModel.GetType() == typeof(XmlSchemaComplexContent))
                {
                    XmlSchemaComplexContent complexContent = contentModel as XmlSchemaComplexContent;
                    XmlSchemaVisualComplexContent visualComplexContent = fillVisualComplexContent(ref complexContent, ref parent);
                    visualContentModel = visualComplexContent;
                }
                else if (element.Content.GetType() == typeof(XmlSchemaSimpleContent))
                {
                    XmlSchemaSimpleContent complexContent = contentModel as XmlSchemaSimpleContent;
                    XmlSchemaVisualSimpleContent visualSimpleContent = fillVisualSimpleContent(ref complexContent, ref parent);
                    visualContentModel = visualSimpleContent;
                }

                return visualContentModel;
            }
            else
            {
                return null;
            }
        }

        protected XmlSchemaVisualNotation fillVisualNotation(ref XmlSchemaNotation element, ref XmlSchemaObject parent)
        {
            if (element != null)
            {
                XmlSchemaNotation notation = element;
                XmlSchemaVisualNotation visualNotation = new XmlSchemaVisualNotation(ref notation);

                // ANNOTATION
                XmlSchemaAnnotation ann = element.Annotation;
                XmlSchemaObject annotationParent = visualNotation as XmlSchemaObject;
                XmlSchemaVisualAnnotation visualAnnotation = fillVisualAnnotation(ref ann, ref annotationParent);
                visualNotation.Annotation = visualAnnotation;

                visualNotation.Parent = parent;
                return visualNotation;
            }
            else
            {
                return null;
            }
        }

        // to do: only Annotation part is done
        protected XmlSchemaVisualElement fillVisualElement(ref XmlSchemaElement element, ref XmlSchemaObject parent)
        {
            if (element != null)
            {
                XmlSchemaElement elem = element;
                XmlSchemaVisualElement visualElement = new XmlSchemaVisualElement(ref elem);

                // ANNOTATION
                XmlSchemaAnnotation ann = element.Annotation;
                XmlSchemaObject annotationParent = visualElement as XmlSchemaObject;
                XmlSchemaVisualAnnotation visualAnnotation = fillVisualAnnotation(ref ann, ref annotationParent);
                visualElement.Annotation = visualAnnotation;

                visualElement.Parent = parent;
                return visualElement;
            }
            else
            {
                return null;
            }
        }

        protected XmlSchemaVisualSimpleType fillVisualSimpleType(ref XmlSchemaSimpleType element, ref XmlSchemaObject parent)
        {
            if (element != null)
            {
                XmlSchemaSimpleType simpleType = element;
                XmlSchemaVisualSimpleType visualSimpleType = new XmlSchemaVisualSimpleType(ref simpleType);

                // ANNOTATION
                XmlSchemaAnnotation ann = element.Annotation;
                XmlSchemaObject annotationParent = visualSimpleType as XmlSchemaObject;
                XmlSchemaVisualAnnotation visualAnnotation = fillVisualAnnotation(ref ann, ref annotationParent);
                visualSimpleType.Annotation = visualAnnotation;

                // CONTENT
                XmlSchemaSimpleTypeContent simpleTypeContent = element.Content;
                XmlSchemaObject simpleTypeContentParent = visualSimpleType as XmlSchemaObject;
                XmlSchemaVisualSimpleTypeContent visualSimpleTypeContent = fillVisualSimpleTypeContent(ref simpleTypeContent, ref simpleTypeContentParent);
                visualSimpleType.Content = visualSimpleTypeContent;

                visualSimpleType.Parent = parent;
                return visualSimpleType;
            }
            else
            {
                return null;
            }
        }

        protected XmlSchemaVisualSimpleTypeContent fillVisualSimpleTypeContent(ref XmlSchemaSimpleTypeContent element, ref XmlSchemaObject parent)
        {
            if (element != null)
            {
                XmlSchemaSimpleTypeContent simpleTypeContent = element;
                XmlSchemaVisualSimpleTypeContent visualSimpleTypeContent = new XmlSchemaVisualSimpleTypeContent(ref simpleTypeContent);

                if (element.GetType() == typeof(XmlSchemaSimpleTypeUnion))
                {
                    XmlSchemaSimpleTypeUnion simpleTypeUnion = element as XmlSchemaSimpleTypeUnion;
                    XmlSchemaVisualSimpleTypeUnion visualSimpleTypeUnion = fillVisualSimpleTypeUnion(ref simpleTypeUnion, ref parent);
                    visualSimpleTypeContent = visualSimpleTypeUnion;
                }
                else if (element.GetType() == typeof(XmlSchemaSimpleTypeList))
                {
                    XmlSchemaSimpleTypeList simpleTypeList = element as XmlSchemaSimpleTypeList;
                    XmlSchemaVisualSimpleTypeList visualSimpleTypeList = fillVisualSimpleTypeList(ref simpleTypeList, ref parent);
                    visualSimpleTypeContent = visualSimpleTypeList;
                }
                else if (element.GetType() == typeof(XmlSchemaSimpleTypeRestriction))
                {
                    XmlSchemaSimpleTypeRestriction simpleTypeRestriction = element as XmlSchemaSimpleTypeRestriction;
                    XmlSchemaVisualSimpleTypeRestriction visualSimpleTypeRestriction = fillVisualSimpleTypeRestriction(ref simpleTypeRestriction, ref parent);
                    visualSimpleTypeContent = visualSimpleTypeRestriction;
                }

                visualSimpleTypeContent.Parent = parent;
                return visualSimpleTypeContent;
            }
            else
            {
                return null;
            }

        }

        protected XmlSchemaVisualSimpleTypeList fillVisualSimpleTypeList(ref XmlSchemaSimpleTypeList element, ref XmlSchemaObject parent)
        {
            if (element != null)
            {
                XmlSchemaVisualSimpleTypeList visualSimpleTypeList = new XmlSchemaVisualSimpleTypeList(ref element);

                // BASE ITEM TYPE
                XmlSchemaObject baseItemTypeParent = visualSimpleTypeList as XmlSchemaObject;
                XmlSchemaSimpleType baseItemType = element.BaseItemType;
                XmlSchemaVisualSimpleType visualBaseItemType = fillVisualSimpleType(ref baseItemType, ref baseItemTypeParent);
                visualSimpleTypeList.BaseItemType = visualBaseItemType;

                // ANNOTATION
                XmlSchemaAnnotation ann = element.Annotation;
                XmlSchemaObject annotationParent = visualSimpleTypeList as XmlSchemaObject;
                XmlSchemaVisualAnnotation visualAnnotation = fillVisualAnnotation(ref ann, ref annotationParent);
                visualSimpleTypeList.Annotation = visualAnnotation;

                visualSimpleTypeList.Parent = parent;
                return visualSimpleTypeList;
            }
            else
            {
                return null;
            }
        }

        protected XmlSchemaVisualSimpleTypeRestriction fillVisualSimpleTypeRestriction(ref XmlSchemaSimpleTypeRestriction element, ref XmlSchemaObject parent)
        {
            XmlSchemaSimpleTypeRestriction simpleTypeRestriction = element;
            XmlSchemaVisualSimpleTypeRestriction visualSimpleTypeRestriction = new XmlSchemaVisualSimpleTypeRestriction(ref simpleTypeRestriction);

            // ANNOTATION
            XmlSchemaAnnotation ann = element.Annotation;
            XmlSchemaObject annotationParent = visualSimpleTypeRestriction as XmlSchemaObject;
            XmlSchemaVisualAnnotation visualAnnotation = fillVisualAnnotation(ref ann, ref annotationParent);
            visualSimpleTypeRestriction.Annotation = visualAnnotation;

            // FACETS
            visualSimpleTypeRestriction.facets = new XmlSchemaObjectCollection();
            foreach (XmlSchemaObject facet in simpleTypeRestriction.Facets)
            {
                XmlSchemaObject f = facet;
                XmlSchemaObject facetParent = element as XmlSchemaObject;
                XmlSchemaObject visualFacet = fillVisualFacet(ref f, ref facetParent);
                visualSimpleTypeRestriction.facets.Add(visualFacet);
            }


            visualSimpleTypeRestriction.Parent = parent;
            return visualSimpleTypeRestriction;
        }

        protected XmlSchemaObject fillVisualFacet(ref XmlSchemaObject element, ref XmlSchemaObject parent)
        {
            if (element.GetType() == typeof(XmlSchemaLengthFacet))
            {
                XmlSchemaLengthFacet lengthFacet = element as XmlSchemaLengthFacet;
                XmlSchemaVisualLengthFacet visualLengthFacet = fillVisualLengthFacet(ref lengthFacet, ref parent);
                return visualLengthFacet;
            }
            else if (element.GetType() == typeof(XmlSchemaMinLengthFacet))
            {
                XmlSchemaMinLengthFacet minLengthFacet = element as XmlSchemaMinLengthFacet;
                XmlSchemaVisualMinLengthFacet visualMinLengthFacet = fillVisualMinLengthFacet(ref minLengthFacet, ref parent);
                return visualMinLengthFacet;
            }
            else if (element.GetType() == typeof(XmlSchemaMaxLengthFacet))
            {
                XmlSchemaMaxLengthFacet maxLengthFacet = element as XmlSchemaMaxLengthFacet;
                XmlSchemaVisualMaxLengthFacet visualMaxLengthFacet = fillVisualMaxLengthFacet(ref maxLengthFacet, ref parent);
                return visualMaxLengthFacet;
            }
            else if (element.GetType() == typeof(XmlSchemaPatternFacet))
            {
                XmlSchemaPatternFacet patternFacet = element as XmlSchemaPatternFacet;
                XmlSchemaVisualPatternFacet visualPatternFacet = fillVisualPatternFacet(ref patternFacet, ref parent);
                return visualPatternFacet;
            }
            else if (element.GetType() == typeof(XmlSchemaEnumerationFacet))
            {
                XmlSchemaEnumerationFacet enumerationFacet = element as XmlSchemaEnumerationFacet;
                XmlSchemaVisualEnumerationFacet visualEnumerationFacet = fillVisualEnumerationFacet(ref enumerationFacet, ref parent);
                return visualEnumerationFacet;
            }
            else if (element.GetType() == typeof(XmlSchemaMaxInclusiveFacet))
            {
                XmlSchemaMaxInclusiveFacet maxInclusiveFacet = element as XmlSchemaMaxInclusiveFacet;
                XmlSchemaVisualMaxInclusiveFacet visualMaxInclusiveFacet = fillVisualMaxInclusiveFacet(ref maxInclusiveFacet, ref parent);
                return visualMaxInclusiveFacet;
            }
            else if (element.GetType() == typeof(XmlSchemaMaxExclusiveFacet))
            {
                XmlSchemaMaxExclusiveFacet maxExclusiveFacet = element as XmlSchemaMaxExclusiveFacet;
                XmlSchemaVisualMaxExclusiveFacet visualMaxExclusiveFacet = fillVisualMaxExclusiveFacet(ref maxExclusiveFacet, ref parent);
                return visualMaxExclusiveFacet;
            }
            else if (element.GetType() == typeof(XmlSchemaMinInclusiveFacet))
            {
                XmlSchemaMinInclusiveFacet minInclusiveFacet = element as XmlSchemaMinInclusiveFacet;
                XmlSchemaVisualMinInclusiveFacet visualMinInclusiveFacet = fillVisualMinInclusiveFacet(ref minInclusiveFacet, ref parent);
                return visualMinInclusiveFacet;
            }
            else if (element.GetType() == typeof(XmlSchemaMinExclusiveFacet))
            {
                XmlSchemaMinExclusiveFacet minExclusiveFacet = element as XmlSchemaMinExclusiveFacet;
                XmlSchemaVisualMinExclusiveFacet visualMinExlusiveFacet = fillVisualMinExclusiveFacet(ref minExclusiveFacet, ref parent);
                return visualMinExlusiveFacet;
            }
            else if (element.GetType() == typeof(XmlSchemaFractionDigitsFacet))
            {
                XmlSchemaFractionDigitsFacet fractionDigitsFacet = element as XmlSchemaFractionDigitsFacet;
                XmlSchemaVisualFractionDigitsFacet visualFractionDigitsFacet = fillVisualFractionDigitsFacet(ref fractionDigitsFacet, ref parent);
                return visualFractionDigitsFacet;
            }
            else if (element.GetType() == typeof(XmlSchemaTotalDigitsFacet))
            {
                XmlSchemaTotalDigitsFacet totalDigitsFacet = element as XmlSchemaTotalDigitsFacet;
                XmlSchemaVisualTotalDigitsFacet visualTotalDigitsFacet = fillVisualTotalDigitsFacet(ref totalDigitsFacet, ref parent);
                return visualTotalDigitsFacet;
            }
            else if (element.GetType() == typeof(XmlSchemaWhiteSpaceFacet))
            {
                XmlSchemaWhiteSpaceFacet whiteSpaceFacet = element as XmlSchemaWhiteSpaceFacet;
                XmlSchemaVisualWhitespaceFacet visualWhiteSpaceFacet = fillVisualWhiteSpaceFacet(ref whiteSpaceFacet, ref parent);
                return visualWhiteSpaceFacet;
            }
            else
            {
                return null;
            }
        }

        #region fillVisualFacet functions

        protected XmlSchemaVisualLengthFacet fillVisualLengthFacet(ref XmlSchemaLengthFacet element, ref XmlSchemaObject parent)
        {
            if (element != null)
            {
                XmlSchemaVisualLengthFacet visualLengthFacet = new XmlSchemaVisualLengthFacet(ref element);

                // ANNOTATION
                XmlSchemaAnnotation ann = element.Annotation;
                XmlSchemaObject annotationParent = visualLengthFacet as XmlSchemaObject;
                XmlSchemaVisualAnnotation visualAnnotation = fillVisualAnnotation(ref ann, ref annotationParent);
                visualLengthFacet.Annotation = visualAnnotation;

                visualLengthFacet.Parent = parent;
                return visualLengthFacet;
            }
            else
            {
                return null;
            }
        }

        protected XmlSchemaVisualMinLengthFacet fillVisualMinLengthFacet(ref XmlSchemaMinLengthFacet element, ref XmlSchemaObject parent)
        {
            if (element != null)
            {
                XmlSchemaVisualMinLengthFacet visualMinLengthFacet = new XmlSchemaVisualMinLengthFacet(ref element);

                // ANNOTATION
                XmlSchemaAnnotation ann = element.Annotation;
                XmlSchemaObject annotationParent = visualMinLengthFacet as XmlSchemaObject;
                XmlSchemaVisualAnnotation visualAnnotation = fillVisualAnnotation(ref ann, ref annotationParent);
                visualMinLengthFacet.Annotation = visualAnnotation;

                visualMinLengthFacet.Parent = parent;
                return visualMinLengthFacet;
            }
            else
            {
                return null;
            }
        }

        protected XmlSchemaVisualMaxLengthFacet fillVisualMaxLengthFacet(ref XmlSchemaMaxLengthFacet element, ref XmlSchemaObject parent)
        {
            if (element != null)
            {
                XmlSchemaVisualMaxLengthFacet visualMaxLengthFacet = new XmlSchemaVisualMaxLengthFacet(ref element);

                // ANNOTATION
                XmlSchemaAnnotation ann = element.Annotation;
                XmlSchemaObject annotationParent = visualMaxLengthFacet as XmlSchemaObject;
                XmlSchemaVisualAnnotation visualAnnotation = fillVisualAnnotation(ref ann, ref annotationParent);
                visualMaxLengthFacet.Annotation = visualAnnotation;

                visualMaxLengthFacet.Parent = parent;
                return visualMaxLengthFacet;
            }
            else
            {
                return null;
            }
        }

        protected XmlSchemaVisualPatternFacet fillVisualPatternFacet(ref XmlSchemaPatternFacet element, ref XmlSchemaObject parent)
        {
            if (element != null)
            {
                XmlSchemaVisualPatternFacet visualPatternFacet = new XmlSchemaVisualPatternFacet(ref element);

                // ANNOTATION
                XmlSchemaAnnotation ann = element.Annotation;
                XmlSchemaObject annotationParent = visualPatternFacet as XmlSchemaObject;
                XmlSchemaVisualAnnotation visualAnnotation = fillVisualAnnotation(ref ann, ref annotationParent);
                visualPatternFacet.Annotation = visualAnnotation;

                visualPatternFacet.Parent = parent;
                return visualPatternFacet;
            }
            else
            {
                return null;
            }
        }

        protected XmlSchemaVisualEnumerationFacet fillVisualEnumerationFacet(ref XmlSchemaEnumerationFacet element, ref XmlSchemaObject parent)
        {
            if (element != null)
            {
                XmlSchemaVisualEnumerationFacet visualEnumerationFacet = new XmlSchemaVisualEnumerationFacet(ref element);

                // ANNOTATION
                XmlSchemaAnnotation ann = element.Annotation;
                XmlSchemaObject annotationParent = visualEnumerationFacet as XmlSchemaObject;
                XmlSchemaVisualAnnotation visualAnnotation = fillVisualAnnotation(ref ann, ref annotationParent);
                visualEnumerationFacet.Annotation = visualAnnotation;

                visualEnumerationFacet.Parent = parent;
                return visualEnumerationFacet;
            }
            else
            {
                return null;
            }
        }

        protected XmlSchemaVisualMaxInclusiveFacet fillVisualMaxInclusiveFacet(ref XmlSchemaMaxInclusiveFacet element, ref XmlSchemaObject parent)
        {
            if (element != null)
            {
                XmlSchemaVisualMaxInclusiveFacet visualMaxInclusiveFacet = new XmlSchemaVisualMaxInclusiveFacet(ref element);

                // ANNOTATION
                XmlSchemaAnnotation ann = element.Annotation;
                XmlSchemaObject annotationParent = visualMaxInclusiveFacet as XmlSchemaObject;
                XmlSchemaVisualAnnotation visualAnnotation = fillVisualAnnotation(ref ann, ref annotationParent);
                visualMaxInclusiveFacet.Annotation = visualAnnotation;

                visualMaxInclusiveFacet.Parent = parent;
                return visualMaxInclusiveFacet;
            }
            else
            {
                return null;
            }
        }

        protected XmlSchemaVisualMaxExclusiveFacet fillVisualMaxExclusiveFacet(ref XmlSchemaMaxExclusiveFacet element, ref XmlSchemaObject parent)
        {
            if (element != null)
            {
                XmlSchemaVisualMaxExclusiveFacet visualMaxInclusiveFacet = new XmlSchemaVisualMaxExclusiveFacet(ref element);

                // ANNOTATION
                XmlSchemaAnnotation ann = element.Annotation;
                XmlSchemaObject annotationParent = visualMaxInclusiveFacet as XmlSchemaObject;
                XmlSchemaVisualAnnotation visualAnnotation = fillVisualAnnotation(ref ann, ref annotationParent);
                visualMaxInclusiveFacet.Annotation = visualAnnotation;

                visualMaxInclusiveFacet.Parent = parent;
                return visualMaxInclusiveFacet;
            }
            else
            {
                return null;
            }
        }

        protected XmlSchemaVisualMinInclusiveFacet fillVisualMinInclusiveFacet(ref XmlSchemaMinInclusiveFacet element, ref XmlSchemaObject parent)
        {
            if (element != null)
            {
                XmlSchemaVisualMinInclusiveFacet visualMinInclusiveFacet = new XmlSchemaVisualMinInclusiveFacet(ref element);

                // ANNOTATION
                XmlSchemaAnnotation ann = element.Annotation;
                XmlSchemaObject annotationParent = visualMinInclusiveFacet as XmlSchemaObject;
                XmlSchemaVisualAnnotation visualAnnotation = fillVisualAnnotation(ref ann, ref annotationParent);
                visualMinInclusiveFacet.Annotation = visualAnnotation;

                visualMinInclusiveFacet.Parent = parent;
                return visualMinInclusiveFacet;
            }
            else
            {
                return null;
            }
        }

        protected XmlSchemaVisualMinExclusiveFacet fillVisualMinExclusiveFacet(ref XmlSchemaMinExclusiveFacet element, ref XmlSchemaObject parent)
        {
            if (element != null)
            {
                XmlSchemaVisualMinExclusiveFacet visualMinExclusiveFacet = new XmlSchemaVisualMinExclusiveFacet(ref element);

                // ANNOTATION
                XmlSchemaAnnotation ann = element.Annotation;
                XmlSchemaObject annotationParent = visualMinExclusiveFacet as XmlSchemaObject;
                XmlSchemaVisualAnnotation visualAnnotation = fillVisualAnnotation(ref ann, ref annotationParent);
                visualMinExclusiveFacet.Annotation = visualAnnotation;

                visualMinExclusiveFacet.Parent = parent;
                return visualMinExclusiveFacet;
            }
            else
            {
                return null;
            }
        }

        protected XmlSchemaVisualFractionDigitsFacet fillVisualFractionDigitsFacet(ref XmlSchemaFractionDigitsFacet element, ref XmlSchemaObject parent)
        {
            if (element != null)
            {
                XmlSchemaVisualFractionDigitsFacet visualFractionDigitsFacet = new XmlSchemaVisualFractionDigitsFacet(ref element);

                // ANNOTATION
                XmlSchemaAnnotation ann = element.Annotation;
                XmlSchemaObject annotationParent = visualFractionDigitsFacet as XmlSchemaObject;
                XmlSchemaVisualAnnotation visualAnnotation = fillVisualAnnotation(ref ann, ref annotationParent);
                visualFractionDigitsFacet.Annotation = visualAnnotation;

                visualFractionDigitsFacet.Parent = parent;
                return visualFractionDigitsFacet;
            }
            else
            {
                return null;
            }
        }

        protected XmlSchemaVisualTotalDigitsFacet fillVisualTotalDigitsFacet(ref XmlSchemaTotalDigitsFacet element, ref XmlSchemaObject parent)
        {
            if (element != null)
            {
                XmlSchemaVisualTotalDigitsFacet visualTotalDigitsFacet = new XmlSchemaVisualTotalDigitsFacet(ref element);

                // ANNOTATION
                XmlSchemaAnnotation ann = element.Annotation;
                XmlSchemaObject annotationParent = visualTotalDigitsFacet as XmlSchemaObject;
                XmlSchemaVisualAnnotation visualAnnotation = fillVisualAnnotation(ref ann, ref annotationParent);
                visualTotalDigitsFacet.Annotation = visualAnnotation;

                visualTotalDigitsFacet.Parent = parent;
                return visualTotalDigitsFacet;
            }
            else
            {
                return null;
            }
        }

        protected XmlSchemaVisualWhitespaceFacet fillVisualWhiteSpaceFacet(ref XmlSchemaWhiteSpaceFacet element, ref XmlSchemaObject parent)
        {
            if (element != null)
            {
                XmlSchemaVisualWhitespaceFacet visualWhitespaceFacet = new XmlSchemaVisualWhitespaceFacet(ref element);

                // ANNOTATION
                XmlSchemaAnnotation ann = element.Annotation;
                XmlSchemaObject annotationParent = visualWhitespaceFacet as XmlSchemaObject;
                XmlSchemaVisualAnnotation visualAnnotation = fillVisualAnnotation(ref ann, ref annotationParent);
                visualWhitespaceFacet.Annotation = visualAnnotation;

                visualWhitespaceFacet.Parent = parent;
                return visualWhitespaceFacet;
            }
            else
            {
                return null;
            }
        }

        #endregion

        protected XmlSchemaVisualSimpleTypeUnion fillVisualSimpleTypeUnion(ref XmlSchemaSimpleTypeUnion element, ref XmlSchemaObject parent)
        {
            if (element != null)
            {
                XmlSchemaSimpleTypeUnion simpleTypeUnion = element;
                XmlSchemaVisualSimpleTypeUnion visualSimpleTypeUnion = new XmlSchemaVisualSimpleTypeUnion(ref simpleTypeUnion);

                // ANNOTATION
                XmlSchemaAnnotation ann = element.Annotation;
                XmlSchemaObject annotationParent = visualSimpleTypeUnion as XmlSchemaObject;
                XmlSchemaVisualAnnotation visualAnnotation = fillVisualAnnotation(ref ann, ref annotationParent);
                visualSimpleTypeUnion.Annotation = visualAnnotation;

                // BASE TYPES
                visualSimpleTypeUnion.BaseTypes = new XmlSchemaObjectCollection();
                foreach (XmlSchemaSimpleType obj in simpleTypeUnion.BaseTypes)
                {
                    XmlSchemaSimpleType simpleType = obj;
                    XmlSchemaVisualSimpleType visualSimpleType = fillVisualSimpleType(ref simpleType, ref parent);
                    visualSimpleTypeUnion.BaseTypes.Add(visualSimpleType);
                }

                visualSimpleTypeUnion.Parent = parent;
                return visualSimpleTypeUnion;
            }
            else
            {
                return null;
            }
        }

        // to do: only Annotation part is done
        protected XmlSchemaVisualGroup fillVisualGroup(ref XmlSchemaGroup element, ref XmlSchemaObject parent)
        {
            if (element != null)
            {
                XmlSchemaGroup group = element;
                XmlSchemaVisualGroup visualGroup = new XmlSchemaVisualGroup(ref group);

                // ANNOTATION
                XmlSchemaAnnotation ann = element.Annotation;
                XmlSchemaObject annotationParent = visualGroup as XmlSchemaObject;
                XmlSchemaVisualAnnotation visualAnnotation = fillVisualAnnotation(ref ann, ref annotationParent);
                visualGroup.Annotation = visualAnnotation;

                visualGroup.Parent = parent;
                return visualGroup;
            }
            else
            {
                return null;
            }
        }

        protected XmlSchemaVisualAll fillVisualAll(ref XmlSchemaAll element, ref XmlSchemaObject parent) // DONE
        {
            if (element != null)
            {
                XmlSchemaAll all = element;
                XmlSchemaVisualAll visualAll = new XmlSchemaVisualAll(ref all);

                // ANNOTATION
                XmlSchemaAnnotation ann = element.Annotation;
                XmlSchemaObject annotationParent = visualAll as XmlSchemaObject;
                XmlSchemaVisualAnnotation visualAnnotation = fillVisualAnnotation(ref ann, ref annotationParent);
                visualAll.Annotation = visualAnnotation;

                // ELEMENTS
                visualAll.Items = new XmlSchemaObjectCollection();
                foreach (XmlSchemaObject el in all.Items)
                {
                    XmlSchemaElement elem = el as XmlSchemaElement;
                    XmlSchemaObject elemParent = visualAll as XmlSchemaObject;
                    XmlSchemaVisualElement visualElement = fillVisualElement(ref elem, ref elemParent);
                    visualAll.Items.Add(visualElement);
                }

                visualAll.Parent = parent;
                return visualAll;
            }
            else
            {
                return null;
            }
        }

        protected XmlSchemaVisualAny fillVisualAny(ref XmlSchemaAny element, ref XmlSchemaObject parent) // DONE
        {
            if (element != null)
            {
                XmlSchemaAny any = element;
                XmlSchemaVisualAny visualAny = new XmlSchemaVisualAny(ref any);

                // ANNOTATION
                XmlSchemaAnnotation ann = element.Annotation;
                XmlSchemaObject annotationParent = visualAny as XmlSchemaObject;
                XmlSchemaVisualAnnotation visualAnnotation = fillVisualAnnotation(ref ann, ref annotationParent);
                visualAny.Annotation = visualAnnotation;

                visualAny.Parent = parent;
                return visualAny;
            }
            else
            {
                return null;
            }
        }

        protected XmlSchemaVisualAnyAttribute fillVisualAnyAttribute(ref XmlSchemaAnyAttribute element, ref XmlSchemaObject parent) // DONE
        {
            if (element != null)
            {
                XmlSchemaAnyAttribute anyAttribute = element;
                XmlSchemaVisualAnyAttribute visualAnyAttribute = new XmlSchemaVisualAnyAttribute(ref anyAttribute);

                // ANNOTATION
                XmlSchemaAnnotation ann = element.Annotation;
                XmlSchemaObject annotationParent = visualAnyAttribute as XmlSchemaObject;
                XmlSchemaVisualAnnotation visualAnnotation = fillVisualAnnotation(ref ann, ref annotationParent);
                visualAnyAttribute.Annotation = visualAnnotation;

                visualAnyAttribute.Parent = parent;
                return visualAnyAttribute;
            }
            else
            {
                return null;
            }
        }

        protected XmlSchemaVisualComplexContent fillVisualComplexContent(ref XmlSchemaComplexContent element, ref XmlSchemaObject parent) // DONE
        {
            if (element != null)
            {
                XmlSchemaComplexContent complexContent = element;
                XmlSchemaVisualComplexContent visualComplexContent = new XmlSchemaVisualComplexContent(ref complexContent);

                // ANNOTATION
                XmlSchemaAnnotation ann = element.Annotation;
                XmlSchemaObject annotationParent = visualComplexContent as XmlSchemaObject;
                XmlSchemaVisualAnnotation visualAnnotation = fillVisualAnnotation(ref ann, ref annotationParent);
                visualComplexContent.Annotation = visualAnnotation;

                // RESTRICTION | EXTENSION
                if (element.Content.GetType() == typeof(XmlSchemaComplexContentExtension))
                {
                    XmlSchemaComplexContentExtension extension = element.Content as XmlSchemaComplexContentExtension;
                    XmlSchemaObject extensionParent = visualComplexContent as XmlSchemaObject;
                    XmlSchemaVisualComplexContentExtension visualExtension = fillVisualComplexContentExtension(ref extension, ref extensionParent);
                    visualComplexContent.Content = visualExtension;
                }
                else if (element.Content.GetType() == typeof(XmlSchemaComplexContentRestriction))
                {
                    XmlSchemaComplexContentRestriction restriction = element.Content as XmlSchemaComplexContentRestriction;
                    XmlSchemaObject restrictionParent = visualComplexContent as XmlSchemaObject;
                    XmlSchemaVisualComplexContentRestriction visualRestriction = fillVisualComplexContentRestriction(ref restriction, ref restrictionParent);
                    visualComplexContent.Content = visualRestriction;
                }

                visualComplexContent.Parent = parent;
                return visualComplexContent;
            }
            else
            {
                return null;
            }
        }

        protected XmlSchemaVisualSimpleContent fillVisualSimpleContent(ref XmlSchemaSimpleContent element, ref XmlSchemaObject parent)
        {
            if (element != null)
            {
                XmlSchemaSimpleContent simpleContent = element;
                XmlSchemaVisualSimpleContent visualSimpleContent = new XmlSchemaVisualSimpleContent(ref simpleContent);

                // ANNOTATION
                XmlSchemaAnnotation ann = element.Annotation;
                XmlSchemaObject annotationParent = visualSimpleContent as XmlSchemaObject;
                XmlSchemaVisualAnnotation visualAnnotation = fillVisualAnnotation(ref ann, ref annotationParent);
                visualSimpleContent.Annotation = visualAnnotation;

                // RESTRICTION | EXTENSION
                if (element.Content.GetType() == typeof(XmlSchemaSimpleContentExtension))
                {
                    XmlSchemaSimpleContentExtension extension = element.Content as XmlSchemaSimpleContentExtension;
                    XmlSchemaObject extensionParent = visualSimpleContent as XmlSchemaObject;
                    XmlSchemaVisualSimpleContentExtension visualExtension = fillVisualSimpleContentExtension(ref extension, ref extensionParent);
                    visualSimpleContent.Content = visualExtension;
                }
                else if (element.Content.GetType() == typeof(XmlSchemaSimpleContentRestriction))
                {
                    XmlSchemaSimpleContentRestriction restriction = element.Content as XmlSchemaSimpleContentRestriction;
                    XmlSchemaObject restrictionParent = visualSimpleContent as XmlSchemaObject;
                    XmlSchemaVisualSimpleContentRestriction visualRestriction = fillVisualSimpleContentRestriction(ref restriction, ref restrictionParent);
                    visualSimpleContent.Content = visualRestriction;
                }

                visualSimpleContent.Parent = parent;
                return visualSimpleContent;
            }
            else
            {
                return null;
            }
        }

        // to do:
        protected XmlSchemaVisualComplexContentExtension fillVisualComplexContentExtension(ref XmlSchemaComplexContentExtension element, ref XmlSchemaObject parent)
        {
            if (element != null)
            {
                XmlSchemaComplexContentExtension complexContentExtension = element;
                XmlSchemaVisualComplexContentExtension visualComplexContentExtension = new XmlSchemaVisualComplexContentExtension(ref complexContentExtension);

                // ANNOTATION
                XmlSchemaAnnotation ann = element.Annotation;
                XmlSchemaObject annotationParent = visualComplexContentExtension as XmlSchemaObject;
                XmlSchemaVisualAnnotation visualAnnotation = fillVisualAnnotation(ref ann, ref annotationParent);
                visualComplexContentExtension.Annotation = visualAnnotation;

                // ANY ATTRIBUTE

                // ATTRIBUTES

                // PARTICLE

                visualComplexContentExtension.Parent = parent;
                return visualComplexContentExtension;
            }
            else
            {
                return null;
            }
        }

        // to do:
        protected XmlSchemaVisualComplexContentRestriction fillVisualComplexContentRestriction(ref XmlSchemaComplexContentRestriction element, ref XmlSchemaObject parent)
        {
            if (element != null)
            {
                XmlSchemaComplexContentRestriction complexContentRestriction = element;
                XmlSchemaVisualComplexContentRestriction visualComplexContentRestriction = new XmlSchemaVisualComplexContentRestriction(ref complexContentRestriction);

                // ANNOTATION
                XmlSchemaAnnotation ann = element.Annotation;
                XmlSchemaObject annotationParent = visualComplexContentRestriction as XmlSchemaObject;
                XmlSchemaVisualAnnotation visualAnnotation = fillVisualAnnotation(ref ann, ref annotationParent);
                visualComplexContentRestriction.Annotation = visualAnnotation;

                // ANY ATTRIBUTE

                // ATTRIBUTES

                // PARTICLE

                visualComplexContentRestriction.Parent = parent;
                return visualComplexContentRestriction;
            }
            else
            {
                return null;
            }
        }

        // to do:
        protected XmlSchemaVisualSimpleContentExtension fillVisualSimpleContentExtension(ref XmlSchemaSimpleContentExtension element, ref XmlSchemaObject parent)
        {
            if (element != null)
            {
                XmlSchemaSimpleContentExtension simpleContentExtension = element;
                XmlSchemaVisualSimpleContentExtension visualSimpleContentExtension = new XmlSchemaVisualSimpleContentExtension(ref simpleContentExtension);

                // ANNOTATION
                XmlSchemaAnnotation ann = element.Annotation;
                XmlSchemaObject annotationParent = visualSimpleContentExtension as XmlSchemaObject;
                XmlSchemaVisualAnnotation visualAnnotation = fillVisualAnnotation(ref ann, ref annotationParent);
                visualSimpleContentExtension.Annotation = visualAnnotation;

                // ANY ATTRIBUTE

                // ATTRIBUTES

                visualSimpleContentExtension.Parent = parent;
                return visualSimpleContentExtension;
            }
            else
            {
                return null;
            }
        }

        // to do:
        protected XmlSchemaVisualSimpleContentRestriction fillVisualSimpleContentRestriction(ref XmlSchemaSimpleContentRestriction element, ref XmlSchemaObject parent)
        {
            if (element != null)
            {
                XmlSchemaSimpleContentRestriction simpleContentRestriction = element;
                XmlSchemaVisualSimpleContentRestriction visualSimpleContentRestriction = new XmlSchemaVisualSimpleContentRestriction(ref simpleContentRestriction);

                // ANNOTATION
                XmlSchemaAnnotation ann = element.Annotation;
                XmlSchemaObject annotationParent = visualSimpleContentRestriction as XmlSchemaObject;
                XmlSchemaVisualAnnotation visualAnnotation = fillVisualAnnotation(ref ann, ref annotationParent);
                visualSimpleContentRestriction.Annotation = visualAnnotation;

                // SIMPLE TYPE
 
                // FACETS
                
                // ANY ATTRIBUTE

                // ATTRIBUTES

                visualSimpleContentRestriction.Parent = parent;
                return visualSimpleContentRestriction;
            }
            else
            {
                return null;
            }
        }

        #endregion

        #region IModel Members

        public void OpenFile(string filename)
        {
            try
            {
                XmlTextReader reader = new XmlTextReader(filename);
                XmlSchema myschema = XmlSchema.Read(reader, ValidationCallback);

                XmlSchemaSet schemes = new XmlSchemaSet();
                schemes.Add(myschema);
                schemes.Compile();

                visualSchema = new XmlSchemaVisual(ref myschema);

                visualSchema.AttributeGroups = new XmlSchemaObjectCollection();

                // ATTRIBUTE GROUPS
                foreach (XmlSchemaAttributeGroup gr in myschema.AttributeGroups.Values)
                {
                    // create visual node for this group
                    XmlSchemaAttributeGroup g = gr;
                    XmlSchemaVisualAttributeGroup attributeGroup = new XmlSchemaVisualAttributeGroup(ref g);
                    attributeGroup.Parent = visualSchema;

                    // ANNOTATION
                    XmlSchemaAnnotation ann = gr.Annotation;
                    XmlSchemaObject parent = attributeGroup as XmlSchemaObject;
                    XmlSchemaVisualAnnotation visualAnnotation = fillVisualAnnotation(ref ann, ref parent);
                    //visualAnnotation.Parent = attributeGroup;
                    attributeGroup.Annotation = visualAnnotation;

                    // ANY ATTRIBUTE
                    XmlSchemaAnyAttribute anyAttr = gr.AnyAttribute;
                    XmlSchemaObject anyAttributeParent = attributeGroup as XmlSchemaObject;
                    XmlSchemaVisualAnyAttribute visualAnyAttribute = fillVisualAnyAttribute(ref anyAttr, ref anyAttributeParent);
                    attributeGroup.AnyAttribute = visualAnyAttribute;

                    // ATTRIBUTES
                    attributeGroup.Attributes = new XmlSchemaObjectCollection();

                    // Get all the content out of the AttributeGroup
                    foreach (XmlSchemaObject atr in gr.Attributes)
                    {
                        XmlSchemaObject a = atr;
                        XmlSchemaObject visualAttributeParent = attributeGroup as XmlSchemaObject;
                        XmlSchemaObject visualAttribute = fillVisualAttribute(ref a, ref visualAttributeParent);

                        attributeGroup.Attributes.Add(visualAttribute);
                    }

                    // REDEFINED ATTRIBUTE GROUP - to do: traverse this as well
                    XmlSchemaAttributeGroup redefinedGroup = gr.RedefinedAttributeGroup;
                    XmlSchemaVisualAttributeGroup visualRedefinedGroup = new XmlSchemaVisualAttributeGroup(ref redefinedGroup);
                    visualRedefinedGroup.Parent = attributeGroup;
                    attributeGroup.RedefinedAttributeGroup = visualRedefinedGroup;

                    visualSchema.AttributeGroups.Add(attributeGroup);
                }

                // ATTRIBUTES
                visualSchema.Attributes = new XmlSchemaObjectCollection();
                foreach (XmlSchemaObject att in myschema.Attributes.Values)
                {
                    XmlSchemaObject attribute = att;
                    XmlSchemaObject visualAttributeParent = visualSchema as XmlSchemaObject;
                    XmlSchemaObject visualAttribute = fillVisualAttribute(ref attribute, ref visualAttributeParent);
                    visualSchema.Attributes.Add(visualAttribute);
                }

                // ELEMENTS
                visualSchema.Elements = new XmlSchemaObjectCollection();
                foreach (XmlSchemaElement element in myschema.Elements.Values)
                {
                    XmlSchemaElement e = element;
                    XmlSchemaVisualElement visualElement = fillVisualElement(ref e);
                    visualElement.Parent = visualSchema;
                    visualSchema.Elements.Add(visualElement);
                }

                // GROUPS
                XmlSchemaObjectCollection groups = new XmlSchemaObjectCollection();
                foreach (XmlSchemaGroup group in myschema.Groups.Values)
                {
                    XmlSchemaGroup gr = group;
                    XmlSchemaVisualGroup visualGroup = fillVisualGroup(ref gr);
                    visualGroup.Parent = visualSchema;
                    groups.Add(visualGroup);
                }

                // INCLUDES
                //XmlSchemaObjectCollection includes = new XmlSchemaObjectCollection();
                //foreach (XmlSchemaExternal external in myschema.Includes)
                //{
                //    XmlSchemaExternal ex = external;
                //    XmlSchemaVisualExternal visualExternal = fillVisualExternal(ref ex); // to do
                //    visualExternal.Parent = visualSchema;
                //    includes.Add(visualExternal);
                //}

                // ITEMS
                XmlSchemaObjectCollection items = new XmlSchemaObjectCollection();
                foreach (XmlSchemaObject o in myschema.Items)
                {
                    if (o.GetType() == typeof(XmlSchemaAnnotation))
                    {
                        XmlSchemaAnnotation annotation = o as XmlSchemaAnnotation;
                        XmlSchemaObject parent = o;
                        XmlSchemaVisualAnnotation visualAnnotation = fillVisualAnnotation(ref annotation, ref parent);
                        items.Add(visualAnnotation);
                    }
                    else if (o.GetType() == typeof(XmlSchemaAttribute))
                    {
                        XmlSchemaObject attribute = o as XmlSchemaAttribute;
                        XmlSchemaObject parent = o;
                        XmlSchemaObject visualAttribute = fillVisualAttribute(ref attribute, ref parent);
                        items.Add(visualAttribute);
                    }
                    else if (o.GetType() == typeof(XmlSchemaAttributeGroup))
                    {
                        XmlSchemaAttributeGroup attributeGroup = o as XmlSchemaAttributeGroup;
                        XmlSchemaObject parent = o;
                        XmlSchemaVisualAttributeGroup visualAttributeGroup = fillVisualAttributeGroup(ref attributeGroup, ref parent);
                        items.Add(visualAttributeGroup);
                    }
                    else if (o.GetType() == typeof(XmlSchemaComplexType))
                    {
                        XmlSchemaComplexType complexType = o as XmlSchemaComplexType;
                        XmlSchemaObject parent = o;
                        XmlSchemaVisualComplexType visualComplexType = fillVisualComplexType(ref complexType, ref parent);
                        items.Add(visualComplexType);
                    }
                    else if (o.GetType() == typeof(XmlSchemaSimpleType))
                    {
                        // to do:
                        XmlSchemaSimpleType simpleType = o as XmlSchemaSimpleType;
                        XmlSchemaObject parent = o;
                        XmlSchemaVisualSimpleType visualSimpleType = fillVisualSimpleType(ref simpleType, ref parent);

                        items.Add(visualSimpleType);
                    }
                    else if (o.GetType() == typeof(XmlSchemaElement))
                    {
                        // to do:
                        XmlSchemaElement element = o as XmlSchemaElement;
                        XmlSchemaObject parent = o;
                        XmlSchemaVisualElement visualElement = fillVisualElement(ref element, ref parent);

                        items.Add(visualElement);
                    }
                    else if (o.GetType() == typeof(XmlSchemaGroup))
                    {
                        // to do:
                        XmlSchemaGroup group = o as XmlSchemaGroup;
                        XmlSchemaObject parent = o;
                        XmlSchemaVisualGroup visualGroup = fillVisualGroup(ref group, ref parent);

                        items.Add(visualGroup);
                    }
                    else if (o.GetType() == typeof(XmlSchemaNotation))
                    {
                        XmlSchemaNotation notation = o as XmlSchemaNotation;
                        XmlSchemaObject parent = o;
                        XmlSchemaVisualNotation visualNotation = fillVisualNotation(ref notation, ref parent);

                        items.Add(visualNotation);
                    }
                    else
                    {
                        // unknown type
                    }
                }
                visualSchema.Items = items;

                // NOTATIONS
                // to do:

                //Load(document.DocumentElement, null);
            }
            catch (System.Exception e)
            {
                String message = e.Message;
                MessageBox.Show(message);
            }

            //DrawDiagram();
            foreach (Observer o in observers)
            {
                o.showFile();
            }
        }

        public void SaveFile(string filename)
        {
            throw new NotImplementedException();
        }

        public void RegisterObserver(Observer controller)
        {
            observers.Add(controller);
        }

        public void RemoveObserver(Observer controller)
        {
            observers.Remove(controller);
        }

        public String GetOuterXml()
        {
            return "";
        }

        #endregion
    }
}